import java.io.*;

public class JPEGDecoder{
    private int height;     
    private boolean build_new = true;
    private final int BUF_H = 8*1;  

    // Private variables and constants
    private static final int  MSB = 0x80000000;
    private static final int  MAX_HUFFMAN_SUBTREE = 50;   // max size = MAX_HUFFMAN_SUBTREE * 256
    private int nComp;                    //number of Components in a scan
    private int[] qTab[]  = new int[10][];//quantization table for the i-th Comp in a scan
    private int[] dcTab[] = new int[10][];//dc HuffTab for the i-th Comp in a scan
    private int[] acTab[] = new int[10][];//ac HuffTab for the i-th Comp in a scan
    private int nBlock[]  = new int[10];  //number of blocks in the i-th Comp in a scan
                                  //                  i=0, ... ,Ns-1
    private int YH,YV,Xsize,Ysize;
    private int marker ;
    private int marker_index=0;
    private int Ri = 0; // RestartInterval

    private int DU[][][]= new int[10][4][64];   //at most 10 data units in a MCU
                       //at most 4 data units in one component 

    private int x=0, y=0, num=0, yp=0; // the begin point of MCU

    
    private int IDCT_Source[]=new int[64];
    private final static int IDCT_P[] ={
        0,   5,  40,  16,  45,   2,   7,  42,
       21,  56,   8,  61,  18,  47,   1,   4,
       41,  23,  58,  13,  32,  24,  37,  10,
       63,  17,  44,   3,   6,  43,  20,  57,
       15,  34,  29,  48,  53,  26,  39,   9,
       60,  19,  46,  22,  59,  12,  33,  31,
       50,  55,  25,  36,  11,  62,  14,  35,
       28,  49,  52,  27,  38,  30,  51,  54    
     } ;
     private final static int table[] = {
         0,    1, 5,    6,    14,    15,    27,    28, 
         2,    4,    7,    13,    16,    26,    29,    42,
         3,    8,    12,    17,    25,    30,    41,    43,
         9,    11,    18,    24,    31,    40,    44,    53,
         10, 19, 23, 32, 39, 45, 52, 54,
         20, 22, 33, 38, 46, 51, 55, 60,
         21, 34, 37, 47, 50, 56, 59, 61,
         35, 36, 48, 49, 57, 58, 62, 63
     };



    private FrameHeader       FH = new FrameHeader();
    private ScanHeader        SH = new ScanHeader() ;
    private QuantizationTable QT = new QuantizationTable();
    private HuffmanTable      HT = new HuffmanTable();

    private void error(String message) throws Exception{
         throw new Exception(message);
    }

    // Report progress in the range 0...100
    public int progress(){
         if(height==0)
             return 0;
         if(yp>height) return 100;
         return yp*100/height;
    }
    
    public boolean checkBuild(){
    	return this.build_new;
    }
    
    interface PixelArray{
        public void setSize(int width, int height, int buf_h) throws Exception;
        public void setPixel(int x, int y, int argb);
    }

    class ComponentSpec{
       int C,  //Component id
           H,  //Horizontal sampling factor
           V,  //Vertical  ....
           Tq; //Quantization table destination selector
    }

    class FrameHeader{
           int SOF,  //Start of frame in different type
               Lf,   //Length
               P,    //Sample Precision (from the orignal image)
               Y,    //Number of lines
               X,    //Number of samples per line
               Nf;   //Number of component in the frame

           ComponentSpec Comp[];  //Components  C H V Tq

           public int get(InputStream in, int sof) throws Exception{
           //get data from file stream in
           //return 0 : correct       otherwise : error

               int i, temp, count=0, c;
               SOF=sof;
               Lf=get16(in); count+=2;
               P=get8(in);   count++;
               Y=get16(in);  count+=2;
               height=Y;
               X=get16(in);  count+=2;
               //width=X;
               Nf=get8(in);  count++;
               Comp = new ComponentSpec[Nf+1];
               for(i=0; i<=Nf; i++){ Comp[i]= new ComponentSpec();}
               for(i=1; i<=Nf; i++){                 
                   if(count>Lf){
                       error("ERROR: frame format error");
                   }
                   c=get8(in);          count++;
                   if(c>=Lf){
                       error("ERROR: fram format error [c>=Lf]");
                   }
                   Comp[c].C=c;
                   temp=get8(in);       count++;
                   Comp[c].H=temp>>4;
                   Comp[c].V=temp&0x0F;
                   Comp[c].Tq=get8(in); count++;
               }
               if(count!=Lf){
                   error("ERROR: frame format error [Lf!=count]");
               }
               return 1;
           }
    }

    class ScanComponent{
           int Cs,   //Scan component selector
               Td,   //DC table selector
               Ta;   //AC table selector
    }

    class ScanHeader{
          int Ls,  //length
               Ns,  //Number of components in the scan
               Ss,  //Start of spectral or predictor selection
               Se,  //End of spectral selection
               Ah,  
               Al;
    
          ScanComponent Comp[]; //Components Cs Td Ta
                                // from [0] to [Ns-1]
          int get(InputStream in) throws Exception{
             //get data from file stream in
             //return 0 : correct       otherwise : error

             int i,temp,count=0;
             Ls=get16(in);   count+=2;
             Ns=get8(in);    count++;
             Comp = new ScanComponent[Ns];
             for(i=0; i<Ns; i++){
                 Comp[i] = new ScanComponent();
                 if(count>Ls){
                     error("ERROR: scan header format error");
                 }
                 Comp[i].Cs=get8(in); count++;
                 temp=get8(in);       count++;
                 Comp[i].Td=temp>>4;
                 Comp[i].Ta=temp&0x0F;
             }
             Ss=get8(in);    count++;
             Se=get8(in);    count++;
             temp=get8(in);  count++;
             Ah=temp>>4;
             Al=temp&0x0F;
             if(count!=Ls){
                 error("ERROR: scan header format error [count!=Ns]");
             }
             return 1;
          }
    }

    class QuantizationTable{
          int Lq,    //length
              Pq[]=new int[4], //Quantization precision 8 or 16
              Tq[]=new int[4]; //1: this table is presented
          int Q[][]=new int[4][64]; //Tables

          public QuantizationTable(){
              Tq[0]=0; Tq[1]=0; Tq[2]=0; Tq[3]=0;
          }

          int get(InputStream in) throws Exception{
              //get data from file stream in
              //return 0 : correct       otherwise : error

              int i,count=0, temp, t;
              Lq=get16(in); count+=2;
              while(count<Lq){
                 temp=get8(in);  count++;
                 t=temp&0x0F;
                 if(t>3){
                     error("ERROR: Quantization table ID > 3");
                 }
                 Pq[t]=temp>>4;
                 if(Pq[t]==0) Pq[t]=8;
                 else if(Pq[t]==1) Pq[t]=16;
                 else{
                     error("ERROR: Quantization table precision error");
                 }
                 Tq[t]=1;
                 if(Pq[t]==8){
                     for(i=0; i<64; i++){
                          if(count>Lq){
                               error("ERROR: Quantization table format error");
                          }
                          Q[t][i]=get8(in); count++;
                     }
                     EnhanceQuantizationTable(Q[t]);
                 }else{
                     for(i=0; i<64; i++){
                          if(count>Lq){
                             error("ERROR: Quantization table format error");
                          }
                          Q[t][i]=get16(in); count+=2;
                     }
                     EnhanceQuantizationTable(Q[t]);
                 }
             }
             if(count!=Lq){
                  error("ERROR: Quantization table error [count!=Lq]");
             }
             return 1;
          }
    }

    class HuffmanTable{
          int Lh,    //Length
              Tc[][]   = new int[4][2],   //1: this table is presented
              Th[]     = new int[4],      //1: this table is presented
              L[][][]  = new int[4][2][16],
              V[][][][]= new int[4][2][16][200]; //tables

           public HuffmanTable(){
              Tc[0][0]=0; Tc[1][0]=0; Tc[2][0]=0; Tc[3][0]=0;
              Tc[0][1]=0; Tc[1][1]=0; Tc[2][1]=0; Tc[3][1]=0;
              Th[0]=0; Th[1]=0; Th[2]=0; Th[3]=0;
           }

           int get(InputStream in) throws Exception{
              //get data from file stream in
              //return 0 : correct       otherwise : error

              int i,j,temp,count=0,t,c;
              Lh=get16(in);    count+=2;
              while(count<Lh){
                 temp=get8(in);  count++;
                 t=temp&0x0F;
                 if(t>3){
                     error("ERROR: Huffman table ID > 3");
                 }
                 c=temp>>4;
                 if(c>2){
                     error("ERROR: Huffman table [Table class > 2 ]");
                 }
                 Th[t]=1; Tc[t][c]=1;
                 for(i=0; i<16; i++){
                     L[t][c][i]=get8(in);  count++;
                 }
                 for(i=0; i<16; i++)
                     for(j=0; j<L[t][c][i]; j++){
                         if(count>Lh){
                             error("ERROR: Huffman table format error [count>Lh]");
                         }
                         V[t][c][i][j]=get8(in); count++;
                     }
                 }
                 if(count!=Lh){
                     error("ERROR: Huffman table format error [count!=Lf]");
                 }
                 for(i=0; i<4; i++)
                     for(j=0; j<2; j++)
                         if(Tc[i][j]!=0){
                             Build_HuffTab(HuffTab[i][j],L[i][j],V[i][j]);
                         }
                 return 1;
           }
    }

    private int readNumber(InputStream in) throws Exception{
         int Ld;
         Ld=get16(in);
         if(Ld!=4){
               error("ERROR: Define number format error [Ld!=4]");
         }
         return get16(in);
    }


    private String readComment(InputStream in) throws Exception{
          int Lc, count=0, i;
          StringBuffer sb = new StringBuffer();

          Lc=get16(in);   count+=2;
          for(i=0; count<Lc; i++){
                sb.append((char)get8(in)); count++;
          }
          return sb.toString();
    }

    
    private int readApp(InputStream in) throws Exception{
          int Lp;
          int count=0;
          Lp=get16(in);   count+=2;
          while(count<Lp){
               get8(in); count++;
          }
          return Lp;
    }       


    private final int get8(InputStream in) throws Exception{
       try{
          return in.read();
       }catch(IOException e){
          error("get8() read error: "+e.toString());
          return -1;
       }
    }

    //get  16-bit data 
    private final int get16(InputStream in) throws Exception{
        int temp;
        try{
           temp = in.read();
           temp<<=8;
           return temp | in.read();
       }catch(IOException e){
          error("get16() read error: "+e.toString());
          return -1;
       }
    }




/********************************************************************
Huffman table for fast search: (HuffTab) 8-bit Look up table
  2-layer search architecture, 1st-layer represent 256 node (8 bits)
  if codeword-length > 8 bits, then 
      the entry of 1st-layer = (# of 2nd-layer table) | MSB
      and it is stored in the 2nd-layer
  Size of tables in each layer are 256. 
  HuffTab[*][*][0-256] is always the only 1st-layer table.

  An entry can be:
  (1) (# of 2nd-layer table) | MSB , for code length > 8 in 1st-layer
  (2) (Code length) << 8 | HuffVal
********************************************************************/
   private int HuffTab[][][] = new int[4][2][MAX_HUFFMAN_SUBTREE * 256];

/* Build_HuffTab()
    Parameter:  t       table ID
                c       table class ( 0 for DC, 1 for AC )
                L[i]    # of codewords which length is i
                V[i][j] Huffman Value (length=i)
    Effect: 
        build up HuffTab[t][c] using L and V.
*/

    private void Build_HuffTab(int tab[],int L[],int V[][]) throws Exception{
        int current_table,i,j,n,table_used, temp;
    int k;
    temp=256;
    k=0;
        for(i=0; i<8; i++){  // i+1 is Code length
            for(j=0; j<L[i]; j++){
               for(n=0; n < (temp>>(i+1)); n++){
                  tab[k]=V[i][j] | ((i+1) << 8);
                  k++;
               }
            }
        }
        for(i=1; k<256; i++, k++) tab[k]= i | MSB;
        if(i>50){
           error("ERROR: Huffman table out of memory!");
        }
        table_used=i;
        current_table=1;
        k=0;
        for(i=8; i<16; i++){  // i+1 is Code length
           for(j=0; j<L[i]; j++){
               for(n=0; n < (temp>>(i-7)); n++){
                 tab[current_table*256+k]=V[i][j] | ((i+1)<<8);
                 k++;
               }
               if(k>=256){
                   if(k>256){
                       error("ERROR: Huffman table error(1)!");
                }
                k=0; current_table++;
            }
         }
      }
   }

 

/* HuffmanValue(): 
    return: Huffman Value of table
            0xFF?? if it receives a MARKER
    Parameter:  table   HuffTab[x][y] (ex) HuffmanValue(HuffTab[1][0],...)
                temp    temp storage for remainded bits
                index   index to bit of temp
                in      FILE pointer
    Effect:
        temp  store new remainded bits
        index change to new index
        in    change to new position
    NOTE:
      Initial by   temp=0; index=0;
    NOTE: (explain temp and index)
      temp: is always in the form at calling time or returning time
       |  byte 4  |  byte 3  |  byte 2  |  byte 1  |
       |     0    |     0    | 00000000 | 00000??? |  if not a MARKER
                                               ^index=3 (from 0 to 15)
                                               321    
    NOTE (marker and marker_index):
      If get a MARKER from 'in', marker=the low-byte of the MARKER
        and marker_index=9
      If marker_index=9 then index is always > 8, or HuffmanValue()
        will not be called.
*/



   private int HuffmanValue(int table[],int temp[], int index[], InputStream in) throws Exception{
    int code, input ,mask=0xFFFF;
    if(index[0]<8){
        temp[0] <<= 8;
        input = get8(in);
        if(input==0xFF){
            marker=get8(in);
            if(marker!=0) marker_index=9;
        }
        temp[0] |= input;
    } else index[0] -= 8;
    code=table[temp[0] >> index[0]];
    if((code&MSB)!=0){
        if(marker_index!=0){ marker_index=0; return 0xFF00|marker;}
        temp[0] &= (mask >> (16-index[0]));
        temp[0] <<= 8;
        input = get8(in);
        if(input==0xFF){
            marker=get8(in);
            if(marker!=0) marker_index=9;
        }
        temp[0] |= input;
        code=table[(code&0xFF)*256 + (temp[0] >> index[0])];
        index[0]+=8;
    }
    index[0] += 8 - (code>>8);
    if(index[0]<0) error("index="+index[0]+" temp="+temp[0]+" code="+code+" in HuffmanValue()");
    if(index[0] < marker_index){ marker_index=0; return 0xFF00|marker;}
    temp[0] &= ( mask >> (16-index[0]) );
    return code&0xFF;
}

//get n-bit signed data from file 'in'
// temp is defined as before
// return signed integer or 0x00FF??00 if it sees a MARKER

    private int getn(InputStream in, int n, int temp[], int index[]) throws Exception{
    int result, one=1, n_one=-1;
    int mask=0xFFFF, input;
    if(n==0) return 0;
    index[0] -= n;
    if(index[0]>=0){
        if(index[0] < marker_index){
            marker_index=0; 
            return (0xFF00|marker) << 8;
        }
        result = temp[0]>>index[0];
        temp[0] &= ( mask >> (16-index[0]) );
    }else{
        temp[0] <<= 8;
        input = get8(in);
        if(input==0xFF){
            marker=get8(in);
            if(marker!=0) marker_index=9;
        }
        temp[0] |= input;
        index[0] += 8;
        if(index[0] < 0){
            if(marker_index!=0){
                marker_index=0;
                return (0xFF00|marker) << 8;
            }
            temp[0] <<= 8;
            input = get8(in);
            if(input==0xFF){
                marker=get8(in);
                if(marker!=0) marker_index=9;
            }
            temp[0] |= input;
            index[0] += 8;
        }
        if(index[0]<0) error("index="+index[0]+" in getn()");
        if(index[0]<marker_index){
            marker_index=0;
            return (0xFF00|marker) << 8;
        }
        result = temp[0]>>index[0];
        temp[0] &= ( mask >> (16-index[0]) );
    }
    if( result < (one<<(n-1)) )
        result += (n_one << n) + 1;
    return result;
}

/******************************************************************

  Decode MCU

    DU[i][j][8][8]     the j-th data unit of component i.

******************************************************************/


  private int YUV_to_BGR(int Y,int u,int v){
    if(Y<0) Y=0;
    int tempB,tempG,tempR;
    tempB=Y+((116130*u)>>16);
    if(tempB<0) tempB=0;
    else if(tempB>255) tempB=255;
 
    tempG=Y-((22554*u+46802*v)>>16);
    if(tempG<0) tempG=0;
    else if(tempG>255) tempG=255;
    
    tempR=Y+((91881*v)>>16);
    if(tempR<0) tempR=0;
    else if(tempR>255) tempR=255;

    return  0xff000000 | ((tempR<<16) + (tempG<<8) + tempB);
}


/* output()
    x, y should be the starting point of MCU when calling output(..)
      it means output() should set x,y for the next MCU at the end.
*/


  private void output(PixelArray out) throws Exception{
    int temp_x, temp_8y, temp;
    int k=0;
    int DU10[], DU20[];
    DU10=DU[1][0]; DU20=DU[2][0];

    num++;
    for(int i=0; i<YV; i++){
        for(int j=0; j<YH; j++){
        temp_8y=i*32;
        temp_x=temp=j*4;
            for(int l=0; l<64; l++){
                if(x<Xsize && y<Ysize){
                   out.setPixel(x,y,
                           YUV_to_BGR(DU[0][k][l]+128,DU10[temp_8y+temp_x],DU20[temp_8y+temp_x]));
                }
                x++;
		        if( (x%YH)==0 ) temp_x++;
		        if( (x%8)==0 ){ 
		           y++; 
		           x-=8;
		           temp_x = temp;
		           if( (y%YV)==0 ) temp_8y+=8;
		        }
            }
            k++;
            x+=8;
            y-=8;
        }
        x -= YH*8;
        y += 8;
    }
    x += YH*8;
    y -= YV*8;
    if(x>=Xsize){
        y+=YV*8;
        x=0;
    }
    yp = y;
}

  private void level_shift(int du[], int P) throws Exception{
    int i;
    if(P==8){
        for(i=0; i<64; i++)
            du[i] += 128;
    }else if(P==12){
        for(i=0; i<64; i++)
            du[i] += 2048;
    }else
        error("ERROR: Precision="+P);
}

/* decode_MCU()
     return 0       if correctly decoded
            0xFF??  if it sees a MARKER
*/
 private int decode_MCU(InputStream in, int PrevDC[],
                         int temp[], int index[]) throws Exception
{
        int value,actab[],dctab[];
        int qtab[],Cs;
    
        for(Cs=0; Cs<nComp; Cs++){
	        qtab=qTab[Cs]; actab=acTab[Cs]; dctab=dcTab[Cs];
	        for(int i=0 ; i<nBlock[Cs]; i++){
	        	for(int k=0; k<IDCT_Source.length; k++) 
	        		IDCT_Source[k]=0;
		        value = HuffmanValue(dctab,temp,index,in);
	            if(value>=0xFF00)
	                return value;
		        PrevDC[Cs] = IDCT_Source[0] = PrevDC[Cs] + getn(in,value,temp,index);
		        IDCT_Source[0] *= qtab[0];
		        for(int j=1 ; j<64 ; j++){
		                value = HuffmanValue(actab,temp,index,in);
	                    if(value>=0xFF00)
	                         return value;
		                j += (value>>4) ;
			            if( (value&0x0F) == 0){
			                if( (value>>4) == 0) break ;
			            }else{
			            IDCT_Source[IDCT_P[j]] = 
			                                  getn(in,value&0x0F,temp,index)*qtab[j];
			            }
		        }
		        ScaleIDCT(DU[Cs][i]);
	        }
       }
       return 0;
   }
 
 
// in-place operation
   private void EnhanceQuantizationTable( int qtab[] ){

    int i ;
    for( i = 0 ; i < 8 ; i ++ )
    {
        qtab[table[0*8+i]] *= 90  ;
        qtab[table[4*8+i]] *= 90  ;
        qtab[table[2*8+i]] *= 118 ;
        qtab[table[6*8+i]] *= 49  ;
        qtab[table[5*8+i]] *= 71  ;
        qtab[table[1*8+i]] *= 126 ;
        qtab[table[7*8+i]] *= 25  ;
        qtab[table[3*8+i]] *= 106 ;
    }
    for( i = 0 ; i < 8 ; i ++ )
    {
        qtab[table[0+8*i]] *= 90  ;
        qtab[table[4+8*i]] *= 90  ;
        qtab[table[2+8*i]] *= 118 ;
        qtab[table[6+8*i]] *= 49  ;
        qtab[table[5+8*i]] *= 71  ;
        qtab[table[1+8*i]] *= 126 ;
        qtab[table[7+8*i]] *= 25  ;
        qtab[table[3+8*i]] *= 106 ;
    }
    for( i = 0 ; i < 64 ; i++ ) {
        qtab[i] >>= 6 ;
    }
}

// out-of-place operation
// input: IDCT_Source
// output: matrix
   private void ScaleIDCT(int matrix[]){
    int p[][] = new int[8][8] ;
    int t0 , t1 , t2 , t3, i ;
    int src0, src1, src2, src3, src4, src5, src6, src7;
    int det0, det1, det2, det3, det4, det5, det6, det7;
        int mindex=0;

    for( i = 0 ; i < 8 ; i++ )
    {
        src0 = IDCT_Source[0*8+i] ;
        src1 = IDCT_Source[1*8+i] ;
        src2 = IDCT_Source[2*8+i] - IDCT_Source[3*8+i] ;
        src3 = IDCT_Source[3*8+i] + IDCT_Source[2*8+i] ;
        src4 = IDCT_Source[4*8+i] - IDCT_Source[7*8+i] ;
        src6 = IDCT_Source[5*8+i] - IDCT_Source[6*8+i] ;
        t0   = IDCT_Source[5*8+i] + IDCT_Source[6*8+i] ;
        t1   = IDCT_Source[4*8+i] + IDCT_Source[7*8+i] ;
        src5 = t0 - t1 ;
        src7 = t0 + t1 ;
        //
        det4 =-src4 * 480 - src6 * 192 ;
        det5 = src5 * 384 ;
        det6 = src6 * 480 - src4 * 192 ;
        det7 = src7 * 256 ;
        t0   = src0 * 256 ;
        t1   = src1 * 256 ;
        t2   = src2 * 384 ;
        t3   = src3 * 256 ;
        det3 = t3      ;
        det0 = t0 + t1 ;
        det1 = t0 - t1 ;
        det2 = t2 - t3 ;
        //
        src0 = det0 + det3 ;
        src1 = det1 + det2 ;
        src2 = det1 - det2 ;
        src3 = det0 - det3 ;
        src4 = det6 - det4 - det5  - det7 ;
        src5 = det5 - det6 + det7 ;
        src6 = det6 - det7 ;
        src7 = det7 ;
        //
        p[0][i] = ( src0 + src7 +(1<<12))>>13 ;
        p[1][i] = ( src1 + src6 +(1<<12))>>13 ;
        p[2][i] = ( src2 + src5 +(1<<12))>>13 ;
        p[3][i] = ( src3 + src4 +(1<<12))>>13 ;
        p[4][i] = ( src3 - src4 +(1<<12))>>13 ;
        p[5][i] = ( src2 - src5 +(1<<12))>>13 ;
        p[6][i] = ( src1 - src6 +(1<<12))>>13 ;
        p[7][i] = ( src0 - src7 +(1<<12))>>13 ;
    }
    //
    for( i = 0 ; i < 8 ; i++ )
    {
        src0 = p[i][0] ;
        src1 = p[i][1] ;
        src2 = p[i][2] - p[i][3] ;
        src3 = p[i][3] + p[i][2] ;
        src4 = p[i][4] - p[i][7] ;
        src6 = p[i][5] - p[i][6] ;
        t0   = p[i][5] + p[i][6] ;
        t1   = p[i][4] + p[i][7] ;
        src5 = t0 - t1 ;
        src7 = t0 + t1 ;
        //
        det4 =-src4 * 480 - src6 * 192 ;
        det5 = src5 * 384 ;
        det6 = src6 * 480 - src4 * 192 ;
        det7 = src7 * 256 ;
        t0   = src0 * 256 ;
        t1   = src1 * 256 ;
        t2   = src2 * 384 ;
        t3   = src3 * 256 ;
        det3 = t3      ;
        det0 = t0 + t1 ;
        det1 = t0 - t1 ;
        det2 = t2 - t3 ;
        //
        src0 = det0 + det3 ;
        src1 = det1 + det2 ;
        src2 = det1 - det2 ;
        src3 = det0 - det3 ;
        src4 = det6 - det4 - det5  - det7 ;
        src5 = det5 - det6 + det7 ;
        src6 = det6 - det7 ;
        src7 = det7 ;
        //
        matrix[mindex++] = ( src0 + src7 +(1<<12))>>13 ;
        matrix[mindex++] = ( src1 + src6 +(1<<12))>>13 ;
        matrix[mindex++] = ( src2 + src5 +(1<<12))>>13 ;
        matrix[mindex++] = ( src3 + src4 +(1<<12))>>13 ;
        matrix[mindex++] = ( src3 - src4 +(1<<12))>>13 ;
        matrix[mindex++] = ( src2 - src5 +(1<<12))>>13 ;
        matrix[mindex++] = ( src1 - src6 +(1<<12))>>13 ;
        matrix[mindex++] = ( src0 - src7 +(1<<12))>>13 ;
    }
   }    



    public int decode_init(InputStream in, PixelArray out) throws Exception{
    	
        int current;
        
        if(in==null) return -1;

        x=0; y=0; yp=0; num=0;
        current=get16(in);
        if(current!=0xFFD8){  //SOI
            error("Not a JPEG file");
            return -1;
        }
        current=get16(in);
        while(current>>4 != 0x0FFC){   //SOF 0~15
            switch(current){
            case 0xFFC4:  //DHT
                HT.get(in); break;
            case 0xFFCC:  //DAC
                error("Program doesn't support arithmetic coding. (format error)");
                return -1;
            case 0xFFDB:
                QT.get(in); break;
            case 0xFFDD:
                Ri = readNumber(in); break;
            case 0xFFE0: case 0xFFE1: case 0xFFE2: case 0xFFE3:
            case 0xFFE4: case 0xFFE5: case 0xFFE6: case 0xFFE7:
            case 0xFFE8: case 0xFFE9: case 0xFFEA: case 0xFFEB:
            case 0xFFEC: case 0xFFED: case 0xFFEE: case 0xFFEF:
                readApp(in); break;
            case 0xFFFE:
                readComment(in); break;
            default:
                if(current>>8 != 0xFF){
                     error("ERROR: format error! (decode)");
                }
            }
            current=get16(in);
        }
        if(current<0xFFC0 || current >0xFFC7){
            error("ERROR: could not handle arithmetic code!");
        }
    
        FH.get(in,current);
        current=get16(in);

        // pix = new int[FH.X * FH.Y];
        out.setSize(FH.X, FH.Y, this.BUF_H);
        
        while(current != 0x0FFDA){   //SOS
            switch(current){
               case 0xFFC4:  //DHT
                   HT.get(in); break;
               case 0xFFCC:  //DAC
                   error("Program doesn't support arithmetic coding. (format error)");
               case 0xFFDB:
                   QT.get(in); break;
               case 0xFFDD:
                   Ri = readNumber(in); break;
               case 0xFFE0: case 0xFFE1: case 0xFFE2: case 0xFFE3:
               case 0xFFE4: case 0xFFE5: case 0xFFE6: case 0xFFE7:
               case 0xFFE8: case 0xFFE9: case 0xFFEA: case 0xFFEB:
               case 0xFFEC: case 0xFFED: case 0xFFEE: case 0xFFEF:
                   readApp(in); break;
               case 0xFFFE:
                   readComment(in); break;
               default:
                   if(current>>8 != 0xFF){
                       error("ERROR: format error! (Parser.decode)");
                   }
            }
            current=get16(in);
        }

        SH.get(in);
        nComp=(int)SH.Ns;
        for(int i=0; i<nComp; i++){
            int CompN=SH.Comp[i].Cs;
            qTab[i]=QT.Q[FH.Comp[CompN].Tq];
            nBlock[i]=FH.Comp[CompN].V * FH.Comp[CompN].H;
            dcTab[i]=HuffTab[SH.Comp[i].Td][0];
            acTab[i]=HuffTab[SH.Comp[i].Ta][1];
        }
        YH=FH.Comp[1].H; YV=FH.Comp[1].V;
        Xsize=FH.X; Ysize=FH.Y;
        return current;
   }
    
    public int decodeOneBuf(InputStream in, PixelArray out, int c, 
    								int[]PRED, int[] temp, int[]index)throws Exception{
    	int RST_num, m=0, i, current=c, scan_num=0;
    	
    	//reset x, y, yp, num
    	this.x = 0;
    	this.y = 0;
    	this.yp = 0;
    	this.num = 0;
    	
    	do{
            scan_num++;
        	for(RST_num=0;;RST_num++){  //Decode one scan
                int MCU_num;
                if(Ri==0){
                    current=decode_MCU(in,PRED,temp,index);
                                             // 0: correctly decoded
                                             // otherwise: MARKER
                    while(current==0){
                        m++;
                        output(out);
                        if(this.y>=this.BUF_H)
                        	break;
                        current=decode_MCU(in,PRED,temp,index);
                    }
                    break;  //current=MARKER
                }
                for(MCU_num=0; MCU_num<Ri && this.y<this.BUF_H; MCU_num++){
                    current=decode_MCU(in,PRED,temp,index);
                    output(out);
                    System.out.print(MCU_num+"##");
                    //fprintf(show,"%i ",MCU_num);
                    if(current!=0) break;
                }
                if(current==0){
                    if(marker_index!=0){
                         current=(0xFF00|marker);
                         marker_index=0;
                    }else current=get16(in);
                }
                if(current>=0xFFD0 && current<=0xFFD7){
                }else break; //current=MARKER
             }
        	if(current==0xFFDC && scan_num==1){ //DNL
                readNumber(in);
                current=get16(in);
            }
	    }while(current!=0xFFD9 && this.y<this.BUF_H);
    	
    	return current;
    }

}